
/* GCSx
** POPUP.H
**
** Popup and drop-down menus and menubar
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_POPUP_H_
#define __GCSx_POPUP_H_

class PopupItem {
private:
    // Ranges covered by the below arrays
    enum {
        ACCEL_LABEL_LOWER_FIRST = 8,
        ACCEL_LABEL_LOWER_LAST = 127,
        ACCEL_LABEL_UPPER_FIRST = 273,
        ACCEL_LABEL_UPPER_LAST = 296,
        
        // Max size of a popup item
        POPUP_MAX_WIDTH = 30,
    };
    
    // All possible accellerator keys in English
    static const char* accelLabelsLower[ACCEL_LABEL_LOWER_LAST - ACCEL_LABEL_LOWER_FIRST + 1];
    static const char* accelLabelsUpper[ACCEL_LABEL_UPPER_LAST - ACCEL_LABEL_UPPER_FIRST + 1];

    // Fills accelLabel and accel    
    void prepAccellabel(Sint32 pKey);

    std::string label; // menu item text

public:
    enum PopupState {
        // Popup states- only 'grayed' applies to menubars
        POPUP_NONE = 0,
        POPUP_DYNAMIC = 1,
        POPUP_CHECKBOX = 2, // Temporary- set each time via supportsCommand
        POPUP_RADIO = 4, // Temporary- set each time via supportsCommand
        POPUP_HIDDEN = 8, // Temporary- set each time via supportsCommand
        POPUP_SEPARATOR = 16,
        POPUP_CHECKED = 32, // Temporary- set each time via supportsCommand
        POPUP_GRAYED = 64, // Temporary- set each time via supportsCommand
    };
    
    const std::string& getLabel() const;
    void setLabel(const std::string& newLabel);

    int code; // positive value that represents this item uniquely
    std::string accelLabel; // accel reminder text
    class PopupMenu* submenu; // menu to expand to, NULL for a normal item
    Sint32 accel; // accellerator for item

    int underline; // underline for shortcut key
    char shortcut; // shortcut key
    PopupState state; // current state, from above #defines
    
    int pos; // X offset for menubar, Y offset for popups
    
    PopupItem();
    // (label of NULL for separator)
    // Dynamic popups call supportsCommand to determine grey/hide/check/radio status
    // Item with or without accellerator (no submenu allowed with accellerator)
    PopupItem(int pCode, const char* pLabel, Sint32 pKey, int dynamic, class PopupMenu* pSubmenu = NULL);
};

class PopupMenu : public Window {
protected:
    int numItems;
    std::vector<PopupItem> items;
    
    int isMenubar;
    int fromMenubar;
    int isEmpty; // Temporary- recalculated each time it pops up
    int accelOffset; // Margin before accellerator notes- popups only
    
    int currSel;
    int submenuLevel;
    int checkboxX;
    int checkboxY;
    void predraw(int xPos, int yPos);

    enum {
        // height of entire separator and width of line itself
        GUI_POPUP_SEPHEIGHT = 7,
        GUI_POPUP_SEPLINE = 2,
        // padding below each text line
        GUI_POPUP_LINEPAD = 1,
        // padding on all four edges
        GUI_POPUP_EDGEPAD = 4,
        // margin on left and right for checkboxes and arrows
        GUI_POPUP_MARGIN = 20,
        // padding between item and it's accellerator note
        GUI_POPUP_GUTTER = 10,

        // menubar-
        // padding to each side of an item
        GUI_MENUBAR_TOPPAD = 2,
        GUI_MENUBAR_BOTTOMPAD = 6,
        GUI_MENUBAR_SIDEPAD = 6,
        // Padding to the left of entire bar
        GUI_MENUBAR_LEFTPAD = 2,
    };

    static const std::string wtSubmenu;
    static const std::string emptyItem;
    static int checkboxSize;

public:

    // Constructor-
    //
    // 'menubar' determines if this is a menubar or a popup menu
    // (menubars do not properly support disabled, checkbox, radio button, separator)
    PopupMenu(int menubar);
    ~PopupMenu();

    // Adds an item; modifies original by adding shortcut key
    void add(PopupItem& item);

#ifndef NDEBUG
    const char* debugDump() const;
#endif
    
    void resolutionChange(int fromW, int fromH, int fromBpp, int toW, int toH, int toBpp);
    void display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset);

    // Pops up as close to the given location as possible and returns
    // Adds self to gui onscreen
    // Adds a SDL_COMMAND event to the queue when complete
    void popup(int xPos, int yPos, int newSubmenuLevel = 0, int isFromMenubar = 0);
    
    // Changes status of the menubar
    void menubar(int show);
    
    // (close all open submenus at a certain level or higher; return count)
    int closeAllSubmenus(int level);
    
    int wantsToBeDeleted() const;
    int event(int hasFocus, const SDL_Event* event);
    int isDocked() const;
    int tempFocus() const;
    WindowType windowType() const;
    WindowSort windowSort() const;
    
    // Quickly generates a popup menu from an array of structures
    // You are responsible for deleting it
    struct PopupGen {
        int code; // Command, or MENU_SUB / MENU_SEP / 0 (0 to end menu / submenu)
        const char* name; // NULL ok for SEP
        int dynamic; // 1 if dynamic; for MENU_SUB, a command code if dynamic
    };
    // (pos is used for recursion and should be left as NULL for initial call)
    static PopupMenu* compileMenu(const PopupGen* menuData, int isMenuBar = 0, int* pos = NULL);
};

#endif

